feat(pmoves-ai): Add PMOVES.AI integration patterns#3
feat(pmoves-ai): Add PMOVES.AI integration patterns#3POWERFULMOVES merged 4 commits intoPMOVES.AI-Edition-Hardenedfrom
Conversation
- Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml) - Add tier-based environment loading (env.shared, env.tier-agent.sh) - Add health check module (pmoves_health/) - Add NATS service announcer (pmoves_announcer/) - Add service registry client (pmoves_registry/) - Add Docker Compose YAML anchors (docker-compose.pmoves.yml) - Add integration documentation (PMOVES.AI_INTEGRATION.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Warning
|
| Cohort / File(s) | Summary |
|---|---|
Documentation PMOVES.AI_INTEGRATION.md |
New integration guide describing setup, env files, compose augmentation, health check and NATS announcement workflows, testing, and created artifacts. |
Secrets Manifest chit/secrets_manifest_v2.yaml |
New CHIT v2 secrets manifest template with precedence (env, CHIT Vault), required/optional variables, env-specific groups, and validation settings. |
Docker Compose Anchors docker-compose.pmoves.yml |
New reusable Docker Compose anchors and templates for env loading, tier-specific anchors (api, agent, worker, data, llm, media), healthchecks, GPU resources, and Prometheus labels; includes commented examples. |
Shared Env env.shared |
New base environment file exporting defaults for PMOVES services (identifiers, NATS, TensorZero, GPU orchestrator, data services, Supabase, monitoring, Archon, proxies, vault, timeouts, health checks). |
Agent Tier Env env.tier-agent.sh |
New agent-tier shell env file exporting TIER=agent and agent-specific defaults (concurrency, timeouts, task queue, MCP, state backend, LLM defaults, prompt/cache settings). |
Service Announcer pmoves_announcer/__init__.py |
New module: ServiceTier enum, ServiceAnnouncement dataclass (serialize/deserialize), ServiceAnnouncer (announce, retry), announce_service helper, and BackgroundAnnouncer for periodic announcements via NATS on subject services.announce.v1. |
Health Framework pmoves_health/__init__.py |
New health framework: HealthStatus constants, DependencyCheck base class and DatabaseCheck/HTTPCheck/NATSCheck, HealthChecker orchestrator, decorator/helpers, get_health_status, and optional FastAPI router/app exposing /healthz. |
Service Registry pmoves_registry/__init__.py |
New service discovery: ServiceTier enum, ServiceInfo dataclass, ServiceNotFoundError, env-override and DNS fallback resolution, async APIs get_service_info, get_service_url, check_service_health, and CommonServices map. |
Sequence Diagram
sequenceDiagram
participant Service as Service Instance
participant NATS as NATS Broker
participant Registry as Service Registry
participant Consumer as Consumer Service
participant Health as Health Checker
Service->>Service: create_announcement()
Service->>NATS: publish(ServiceAnnouncement) on services.announce.v1
NATS-->>NATS: distribute message
Consumer->>Registry: get_service_info(slug)
Registry->>Registry: check environment overrides
alt env override found
Registry-->>Consumer: return ServiceInfo (env)
else
Registry->>Registry: construct DNS fallback URL
Registry-->>Consumer: return ServiceInfo (fallback)
end
Consumer->>Health: check_service_health(slug)
Health->>Consumer: HTTP GET /healthz -> status (200/503)
Consumer-->>Health: interpret boolean result
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
🐰 I nibble anchors, hop through env lines,
I trumpet NATS and health-check chimes;
Registry maps the burrow's gate,
Announcements bounce—oh how great!
A tiny rabbit cheers: PMOVES takes flight! ✨
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 74.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title 'feat(pmoves-ai): Add PMOVES.AI integration patterns' clearly and concisely summarizes the main change—adding PMOVES.AI integration components to the codebase. |
| Description check | ✅ Passed | The PR description comprehensively covers the template requirements with all major sections completed: summary, detailed changes, type of change (new feature), affected services (Docker/Infrastructure), testing examples, and a completed checklist. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c66dd80dec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def health_check(checks: List[DependencyCheck] = None): | ||
| """Decorator to add health checks to a function.""" | ||
| def decorator(func: Callable): | ||
| @wraps(func) | ||
| async def wrapper(*args, **kwargs): | ||
| checker = _health_checker | ||
| if checks: | ||
| for check in checks: | ||
| checker.add_check(check) |
There was a problem hiding this comment.
Avoid re-adding checks on every health request
The health_check decorator mutates the global _health_checker on every invocation by re-adding the same checks, so a long-running service that is polled frequently (e.g., k8s/Compose health checks) will keep appending duplicate checks. This makes each health request progressively slower and can lead to timeouts or unnecessary load on dependencies. Consider registering checks once at startup or deduplicating before appending.
Useful? React with 👍 / 👎.
| # Agent Tier Environment | ||
| x-env-tier-agent: &env-tier-agent | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-agent # Agent tier specific configuration |
There was a problem hiding this comment.
Fix agent tier env_file name mismatch
The compose anchors point at env.tier-agent, but the only file added in this commit is env.tier-agent.sh. As written, the agent-tier anchor won’t load any tier-specific variables (and the referenced file doesn’t exist), so services using *env-tier-agent will miss the intended configuration. Either rename the file or update the anchor to match the actual filename.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 Fix all issues with AI agents
In `@docker-compose.pmoves.yml`:
- Around line 18-97: The docker-compose uses env_file entries (x-pmoves-env /
x-env-tier-*) pointing to script-style files (env.shared, env.tier-agent, etc.)
which won't be parsed as dotenv; either convert those scripts into dotenv format
(KEY=VALUE lines with no export or ${VAR:-default} expressions) and ensure
filenames match (e.g., env.tier-agent -> env.tier-agent or update compose to
env.tier-agent.sh), or stop using env_file and instead source the .sh files
before running compose (e.g., require "source env.shared && source
env.tier-agent.sh" prior to docker compose up) or add a build step that
generates proper dotenv files from the scripts; fix references to env.tier-agent
/ env.tier-worker / env.tier-llm etc. so the filenames used in env_file exactly
match the filesystem.
In `@env.shared`:
- Around line 13-63: The env.shared file currently sets PMOVES_ENV to production
and provides insecure default credentials (e.g., NEO4J_USERNAME/NEO4J_PASSWORD,
MINIO_ACCESS_KEY/MINIO_SECRET_KEY); change these defaults so production is not
the implicit default and credentials are not filled: set PMOVES_ENV to a
non-production default (e.g., development) or require explicit override, and
replace sensitive defaults for NEO4J_PASSWORD, MINIO_SECRET_KEY,
MINIO_ACCESS_KEY (and any other credentials like MEILISEARCH_API_KEY,
QDRANT_API_KEY) with empty values or a clear sentinel like "CHANGE_ME" so
deployers must supply secure credentials; ensure documentation/validation
enforces providing real secrets for production environments referenced by the
SERVICE_NAME/SERVICE_SLUG variables.
In `@env.tier-agent.sh`:
- Around line 1-4: env.tier-agent.sh is missing a shell directive which triggers
ShellCheck SC2148; add a POSIX-compatible shebang as the first line of
env.tier-agent.sh (for example using env to pick bash) so the script has a
declared shell and CI/ShellCheck will pass, and verify the file starts with that
line and is saved with proper line endings.
In `@envared`:
- Around line 51-63: Remove hard-coded default credentials and force explicit
overrides: stop assigning defaults for NEO4J_USERNAME, NEO4J_PASSWORD,
MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY in the env file (do
not default to "neo4j"/"minioadmin"/empty API keys); instead leave them unset or
empty and add startup validation logic that checks these environment variables
and fails fast with a clear error if they are missing. Also avoid defaulting
PMOVES_ENV to "production" without explicit intent—require it be set or validate
allowed values at startup. Use the environment variable names (NEO4J_USERNAME,
NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, MINIO_SECRET_KEY,
PMOVES_ENV) to locate and change the assignments and to implement the
validation.
In `@pmoves_announcer/__init__.py`:
- Around line 7-9: Update the usage snippet in __init__.py to import from the
correct package name: change the example that currently says "from
service_announcer import ServiceAnnouncer, announce_service" so it references
the actual module "pmoves_announcer" and still mentions the exported symbols
ServiceAnnouncer and announce_service; ensure the docstring/usage block
consistently shows "from pmoves_announcer import ServiceAnnouncer,
announce_service" so consumers see the correct import path.
- Around line 169-185: Replace the insecure print in the announcement error
handler with structured logging that does not interpolate the raw exception or
the nats_url; inside the except block (surrounding ServiceAnnouncement creation
and NATS.connect calls) call your module or instance logger (e.g., logger.error)
with a sanitized message like "Failed to announce service" and attach
non-sensitive context such as the exception class name (type(e).__name__) or an
error code rather than e.__str__(), ensuring no NATS URL or credentials are
logged; keep returning False after logging.
In `@pmoves_health/__init__.py`:
- Around line 188-198: The decorator health_check currently mutates
_health_checker by calling checker.add_check(check) inside wrapper on every
invocation, causing duplicate checks; move the logic that registers checks to
decoration time (inside decorator before defining wrapper) or guard for
duplicates there — e.g., iterate over the provided checks once in health_check's
decorator scope and call _health_checker.add_check(check) (or check existing
_health_checker.checks to avoid duplicates) so wrapper only calls func and does
not modify _health_checker on each call.
In `@pmoves_registry/__init__.py`:
- Around line 4-9: The module header claims a 4-step fallback chain (env,
Supabase, NATS, Docker DNS) but get_service_info only uses environment variables
and DNS; update the implementation or the docstring to match reality. Either
implement Supabase lookups and NATS announcements in get_service_info (add a
Supabase client call to query the service catalog by service name and a NATS
subscriber/cache lookup to check recent announcements, using identifiable
functions like get_service_info and any existing cache/NATS helper), or simplify
the module docstring to list only the actually-implemented fallbacks (env and
DNS) and remove Supabase/NATS from the header. Ensure references to
get_service_info and any new helpers are consistent and add minimal error
handling/logging around external calls.
- Around line 147-166: The env-override branch that constructs ServiceInfo when
_get_env_url(slug) returns a base URL must ensure health_check_url points to a
health endpoint rather than the bare base (modify the ServiceInfo creation in
the env block that builds slug/name/health_check_url); detect if env_url already
ends with a known health suffix (e.g., "/health", "/healthz", "/status",
"/ready") and use it as-is, otherwise append "/healthz" (preserving any trailing
slash behavior) before assigning health_check_url so check_service_health won't
404.
In `@PMOVES.AI_INTEGRATION.md`:
- Around line 73-78: The markdown list item for "Health Check" uses a bare URL
which violates MD034; update the list item "- **Health Check:**
http://localhost:8091/healthz" to use angle-bracket or link syntax (e.g., "-
**Health Check:** <http://localhost:8091/healthz>" or "- **Health Check:**
[http://localhost:8091/healthz](http://localhost:8091/healthz)") so the URL is
not bare and MD034 is satisfied.
- Around line 13-15: Update the docs to reference the correct filename
`env.tier-agent.sh` (replace the incorrect `env.tier-agent`) and hyphenate
“tier-specific” everywhere; locate the list entry that currently reads
`env.tier-agent - AGENT tier specific configuration` and change it to
`env.tier-agent.sh - AGENT tier-specific configuration`.
🧹 Nitpick comments (3)
pmoves_registry/__init__.py (1)
40-63: Validate env/DNS-derivedServiceInfowith Pydantic.
ServiceInfois built from external strings (env/DNS) without validation; malformed URLs can slip through and fail later. Consider a Pydantic model (e.g.,AnyUrlforhealth_check_url, constrainedslug) to raise validation errors early. As per coding guidelines, use Pydantic to raise validation errors for bad data.pmoves_announcer/__init__.py (1)
88-102: Use Pydantic to validate announcement payloads.
from_jsonaccepts untrusted data and will either silently coerce types or raiseKeyError/ValueErrorlater. A Pydantic model (e.g.,AnyUrlforurl/health_check, constrainedport) can fail fast and return actionable errors. As per coding guidelines, use Pydantic to raise validation errors for bad data.pmoves_health/__init__.py (1)
72-105: Validate HTTP/NATS URLs instead of masking bad inputs.
Invalid URLs are currently swallowed and reported asFalse, which hides configuration errors. Consider Pydantic validation (e.g.,AnyUrl) at registration time to raise clear errors. As per coding guidelines, use Pydantic to raise validation errors for bad data.
| x-pmoves-env: &pmoves-env-base | ||
| env_file: | ||
| - env.shared # Base PMOVES.AI configuration | ||
| environment: | ||
| - PMOVES_ENV=${PMOVES_ENV:-production} | ||
| - TIER=${TIER} | ||
| - NATS_URL=${NATS_URL:-nats://nats:4222} | ||
| - TENSORZERO_URL=${TENSORZERO_URL:-http://tensorzero-gateway:3030} | ||
|
|
||
| # API Tier Environment | ||
| x-env-tier-api: &env-tier-api | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-api # API tier specific configuration | ||
| environment: | ||
| - TIER=api | ||
| - MAX_CONCURRENT_REQUESTS=${MAX_CONCURRENT_REQUESTS:-100} | ||
| - RATE_LIMIT_ENABLED=${RATE_LIMIT_ENABLED:-true} | ||
|
|
||
| # Agent Tier Environment | ||
| x-env-tier-agent: &env-tier-agent | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-agent # Agent tier specific configuration | ||
| environment: | ||
| - TIER=agent | ||
| - MAX_CONCURRENT_AGENTS=${MAX_CONCURRENT_AGENTS:-50} | ||
| - MCP_ENABLED=${MCP_ENABLED:-true} | ||
|
|
||
| # Worker Tier Environment | ||
| x-env-tier-worker: &env-tier-worker | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-worker # Worker tier specific configuration | ||
| environment: | ||
| - TIER=worker | ||
| - MAX_CONCURRENT_JOBS=${MAX_CONCURRENT_JOBS:-10} | ||
| - WORKER_POOL_SIZE=${WORKER_POOL_SIZE:-4} | ||
|
|
||
| # Data Tier Environment | ||
| x-env-tier-data: &env-tier-data | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-data # Data tier specific configuration | ||
| environment: | ||
| - TIER=data | ||
| - MAX_CONNECTIONS=${MAX_CONNECTIONS:-100} | ||
|
|
||
| # LLM Tier Environment | ||
| x-env-tier-llm: &env-tier-llm | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-llm # LLM tier specific configuration | ||
| environment: | ||
| - TIER=llm | ||
| - MAX_CONCURRENT_REQUESTS=${MAX_CONCURRENT_REQUESTS:-50} | ||
|
|
||
| # Media Tier Environment | ||
| x-env-tier-media: &env-tier-media | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-media # Media tier specific configuration | ||
| environment: | ||
| - TIER=media | ||
| - GPU_ENABLED=${GPU_ENABLED:-true} | ||
| - MAX_CONCURRENT_JOBS=${MAX_CONCURRENT_JOBS:-4} | ||
|
|
||
| # UI Tier Environment | ||
| x-env-tier-ui: &env-tier-ui | ||
| <<: *pmoves-env-base | ||
| env_file: | ||
| - env.shared | ||
| - env.tier-ui # UI tier specific configuration | ||
| environment: |
There was a problem hiding this comment.
env_file won’t load the current env.shared / env.tier-* scripts.
Line 18-97 uses env_file, but Compose expects dotenv KEY=VALUE files (no export, no ${VAR:-default} evaluation). Also env.tier-agent doesn’t match env.tier-agent.sh, so it won’t be found. This will leave containers missing the intended defaults.
✅ One possible fix (align to dotenv files)
x-pmoves-env: &pmoves-env-base
env_file:
- - env.shared # Base PMOVES.AI configuration
+ - env.shared.env # Dotenv format (KEY=VALUE)
x-env-tier-agent: &env-tier-agent
<<: *pmoves-env-base
env_file:
- - env.shared
- - env.tier-agent # Agent tier specific configuration
+ - env.shared.env
+ - env.tier-agent.envIf you want to keep the .sh scripts, remove env_file and require source env.shared && source env.tier-agent.sh before docker compose up, or generate dotenv files from the scripts.
🤖 Prompt for AI Agents
In `@docker-compose.pmoves.yml` around lines 18 - 97, The docker-compose uses
env_file entries (x-pmoves-env / x-env-tier-*) pointing to script-style files
(env.shared, env.tier-agent, etc.) which won't be parsed as dotenv; either
convert those scripts into dotenv format (KEY=VALUE lines with no export or
${VAR:-default} expressions) and ensure filenames match (e.g., env.tier-agent ->
env.tier-agent or update compose to env.tier-agent.sh), or stop using env_file
and instead source the .sh files before running compose (e.g., require "source
env.shared && source env.tier-agent.sh" prior to docker compose up) or add a
build step that generates proper dotenv files from the scripts; fix references
to env.tier-agent / env.tier-worker / env.tier-llm etc. so the filenames used in
env_file exactly match the filesystem.
| # PMOVES.AI Tier Environment: Agent | ||
| # For Agent and Orchestrator services (Agent Zero, Archon, etc.) | ||
| # Source after env.shared: source env.shared && source env.tier-agent.sh | ||
|
|
There was a problem hiding this comment.
Add a shell directive/shebang to satisfy Shellcheck (SC2148).
Line 1 lacks a declared shell, which can trigger CI failures.
✅ Suggested fix
+#!/usr/bin/env bash
+# shellcheck shell=bash
# PMOVES.AI Tier Environment: Agent📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # PMOVES.AI Tier Environment: Agent | |
| # For Agent and Orchestrator services (Agent Zero, Archon, etc.) | |
| # Source after env.shared: source env.shared && source env.tier-agent.sh | |
| #!/usr/bin/env bash | |
| # shellcheck shell=bash | |
| # PMOVES.AI Tier Environment: Agent | |
| # For Agent and Orchestrator services (Agent Zero, Archon, etc.) | |
| # Source after env.shared: source env.shared && source env.tier-agent.sh | |
🧰 Tools
🪛 Shellcheck (0.11.0)
[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
(SC2148)
🤖 Prompt for AI Agents
In `@env.tier-agent.sh` around lines 1 - 4, env.tier-agent.sh is missing a shell
directive which triggers ShellCheck SC2148; add a POSIX-compatible shebang as
the first line of env.tier-agent.sh (for example using env to pick bash) so the
script has a declared shell and CI/ShellCheck will pass, and verify the file
starts with that line and is saved with proper line endings.
| export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474} | ||
| export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j} | ||
| export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} | ||
|
|
||
| # Meilisearch (Full-Text Search) | ||
| export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700} | ||
| export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-} | ||
|
|
||
| # MinIO (Object Storage) | ||
| export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000} | ||
| export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin} | ||
| export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin} | ||
| export MINIO_REGION=${MINIO_REGION:-us-east-1} |
There was a problem hiding this comment.
Avoid shipping default credentials in the shared base config.
Line 52-63 hard-codes well-known defaults (neo4j/neo4j, minioadmin), while Line 14 defaults PMOVES_ENV to production. This makes it easy to deploy with unsafe credentials.
🔒 Suggested hardening (force explicit overrides)
- export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j}
- export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j}
+ export NEO4J_USERNAME=${NEO4J_USERNAME:-}
+ export NEO4J_PASSWORD=${NEO4J_PASSWORD:-}
- export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
- export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
+ export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-}
+ export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474} | |
| export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j} | |
| export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} | |
| # Meilisearch (Full-Text Search) | |
| export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700} | |
| export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-} | |
| # MinIO (Object Storage) | |
| export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000} | |
| export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin} | |
| export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin} | |
| export MINIO_REGION=${MINIO_REGION:-us-east-1} | |
| export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474} | |
| export NEO4J_USERNAME=${NEO4J_USERNAME:-} | |
| export NEO4J_PASSWORD=${NEO4J_PASSWORD:-} | |
| # Meilisearch (Full-Text Search) | |
| export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700} | |
| export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-} | |
| # MinIO (Object Storage) | |
| export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000} | |
| export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-} | |
| export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-} | |
| export MINIO_REGION=${MINIO_REGION:-us-east-1} |
🤖 Prompt for AI Agents
In `@envared` around lines 51 - 63, Remove hard-coded default credentials and
force explicit overrides: stop assigning defaults for NEO4J_USERNAME,
NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY in
the env file (do not default to "neo4j"/"minioadmin"/empty API keys); instead
leave them unset or empty and add startup validation logic that checks these
environment variables and fails fast with a clear error if they are missing.
Also avoid defaulting PMOVES_ENV to "production" without explicit intent—require
it be set or validate allowed values at startup. Use the environment variable
names (NEO4J_USERNAME, NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY,
MINIO_SECRET_KEY, PMOVES_ENV) to locate and change the assignments and to
implement the validation.
| Service discovery using the PMOVES service registry with fallback chain: | ||
| 1. Environment variables (static overrides) | ||
| 2. Supabase service catalog (dynamic, runtime) | ||
| 3. NATS service announcements (real-time, cached) | ||
| 4. Docker DNS (development fallback) | ||
|
|
There was a problem hiding this comment.
Documented fallback chain isn’t implemented.
The header lists Supabase and NATS resolution, but get_service_info only checks env and DNS. Either implement those steps or update the description to avoid misleading integrators.
🤖 Prompt for AI Agents
In `@pmoves_registry/__init__.py` around lines 4 - 9, The module header claims a
4-step fallback chain (env, Supabase, NATS, Docker DNS) but get_service_info
only uses environment variables and DNS; update the implementation or the
docstring to match reality. Either implement Supabase lookups and NATS
announcements in get_service_info (add a Supabase client call to query the
service catalog by service name and a NATS subscriber/cache lookup to check
recent announcements, using identifiable functions like get_service_info and any
existing cache/NATS helper), or simplify the module docstring to list only the
actually-implemented fallbacks (env and DNS) and remove Supabase/NATS from the
header. Ensure references to get_service_info and any new helpers are consistent
and add minimal error handling/logging around external calls.
| # 1. Check environment variable override | ||
| if env_url := _get_env_url(slug): | ||
| return ServiceInfo( | ||
| slug=slug, | ||
| name=f"{slug} (from env)", | ||
| description=f"Service URL from environment variable", | ||
| health_check_url=env_url, | ||
| default_port=default_port, | ||
| tier=ServiceTier.API, # Default tier | ||
| ) | ||
|
|
||
| # 2. Fallback to DNS-based URL | ||
| fallback_url = _fallback_dns_url(slug, default_port) | ||
| return ServiceInfo( | ||
| slug=slug, | ||
| name=f"{slug} (fallback)", | ||
| description=f"Service resolved via Docker DNS fallback", | ||
| health_check_url=fallback_url, | ||
| default_port=default_port, | ||
| tier=ServiceTier.API, |
There was a problem hiding this comment.
Ensure env URLs map to a health-check URL.
Env vars like HIRAG_V2_URL are base URLs; check_service_health will hit the base and often 404. Append /healthz (or detect an existing health suffix) when building ServiceInfo from env.
🐛 Proposed fix
- if env_url := _get_env_url(slug):
- return ServiceInfo(
+ if env_url := _get_env_url(slug):
+ health_url = env_url.rstrip("/")
+ if not any(health_url.endswith(s) for s in ("/healthz", "/health", "/metrics", "/ping")):
+ health_url = f"{health_url}/healthz"
+ return ServiceInfo(
slug=slug,
name=f"{slug} (from env)",
description=f"Service URL from environment variable",
- health_check_url=env_url,
+ health_check_url=health_url,
default_port=default_port,
tier=ServiceTier.API, # Default tier
)🤖 Prompt for AI Agents
In `@pmoves_registry/__init__.py` around lines 147 - 166, The env-override branch
that constructs ServiceInfo when _get_env_url(slug) returns a base URL must
ensure health_check_url points to a health endpoint rather than the bare base
(modify the ServiceInfo creation in the env block that builds
slug/name/health_check_url); detect if env_url already ends with a known health
suffix (e.g., "/health", "/healthz", "/status", "/ready") and use it as-is,
otherwise append "/healthz" (preserving any trailing slash behavior) before
assigning health_check_url so check_service_health won't 404.
| - `env.shared` - Base environment configuration | ||
| - `env.tier-agent` - AGENT tier specific configuration | ||
| - `chit/secrets_manifest_v2.yaml` - Add your service's required secrets |
There was a problem hiding this comment.
Correct the env file name and hyphenate “tier-specific”.
The PR adds env.tier-agent.sh, but the guide lists env.tier-agent, and “tier-specific” should be hyphenated.
✏️ Proposed fix
-- `env.tier-agent` - AGENT tier specific configuration
+- `env.tier-agent.sh` - AGENT tier-specific configuration📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - `env.shared` - Base environment configuration | |
| - `env.tier-agent` - AGENT tier specific configuration | |
| - `chit/secrets_manifest_v2.yaml` - Add your service's required secrets | |
| - `env.shared` - Base environment configuration | |
| - `env.tier-agent.sh` - AGENT tier-specific configuration | |
| - `chit/secrets_manifest_v2.yaml` - Add your service's required secrets |
🧰 Tools
🪛 LanguageTool
[grammar] ~14-~14: Use a hyphen to join words.
Context: ...guration - env.tier-agent - AGENT tier specific configuration - `chit/secrets_m...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In `@PMOVES.AI_INTEGRATION.md` around lines 13 - 15, Update the docs to reference
the correct filename `env.tier-agent.sh` (replace the incorrect
`env.tier-agent`) and hyphenate “tier-specific” everywhere; locate the list
entry that currently reads `env.tier-agent - AGENT tier specific configuration`
and change it to `env.tier-agent.sh - AGENT tier-specific configuration`.
| - **Name:** Archon Agent Service | ||
| - **Slug:** archon | ||
| - **Tier:** agent | ||
| - **Port:** 8091 | ||
| - **Health Check:** http://localhost:8091/healthz | ||
| - **NATS Enabled:** False |
There was a problem hiding this comment.
Avoid bare URLs in Markdown lists.
Wrap the URL in angle brackets (or link syntax) to satisfy MD034 and render consistently.
✏️ Proposed fix
-- **Health Check:** http://localhost:8091/healthz
+- **Health Check:** <http://localhost:8091/healthz>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - **Name:** Archon Agent Service | |
| - **Slug:** archon | |
| - **Tier:** agent | |
| - **Port:** 8091 | |
| - **Health Check:** http://localhost:8091/healthz | |
| - **NATS Enabled:** False | |
| - **Name:** Archon Agent Service | |
| - **Slug:** archon | |
| - **Tier:** agent | |
| - **Port:** 8091 | |
| - **Health Check:** <http://localhost:8091/healthz> | |
| - **NATS Enabled:** False |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
77-77: Bare URL used
(MD034, no-bare-urls)
🤖 Prompt for AI Agents
In `@PMOVES.AI_INTEGRATION.md` around lines 73 - 78, The markdown list item for
"Health Check" uses a bare URL which violates MD034; update the list item "-
**Health Check:** http://localhost:8091/healthz" to use angle-bracket or link
syntax (e.g., "- **Health Check:** <http://localhost:8091/healthz>" or "-
**Health Check:**
[http://localhost:8091/healthz](http://localhost:8091/healthz)") so the URL is
not bare and MD034 is satisfied.
- Fix deprecated datetime.utcnow() → datetime.now(timezone.utc) - Fix YAML environment merge (list → map for proper merging) - Fix health check decorator accumulation bug - Fix health endpoint status codes (return 503 when unhealthy) - Remove APP/UI tiers (stick to 6-tier architecture) - Fix resource leaks in NATS connections (try/finally)
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@pmoves_announcer/__init__.py`:
- Around line 41-48: The ServiceTier enum is missing APP and UI which causes
ServiceAnnouncement.from_json (tier=ServiceTier(data["tier"])) to raise
ValueError for valid tiers; update ServiceTier to include "app" and "ui" entries
to match pmoves_registry, and change ServiceAnnouncement.from_json to rely on
Pydantic validation (e.g., parse_obj / model instantiation with a Field typed as
ServiceTier) instead of directly calling ServiceTier(...), so invalid values
produce Pydantic ValidationError rather than a bare ValueError.
- Around line 167-183: The current announce flow opens a NATS connection via
NATS.connect but if nc.publish() or nc.flush() raises the connection is never
closed; change the logic in the announce routine to only call NATS.connect
first, then wrap the publish/flush sequence in a try/finally so that await
nc.close() always runs when nc was successfully created; ensure nc is only
referenced if connect succeeded (e.g., set nc = None before connect, assign on
success) and guard the await nc.close() in the finally with a check and
swallow/log any errors from close so cleanup never leaks resources (refer to
NATS, connect, nc.publish, nc.flush, nc.close, create_announcement,
ServiceAnnouncement.SUBJECT).
♻️ Duplicate comments (2)
pmoves_announcer/__init__.py (2)
7-9: Fix module name in usage snippet.The import example references
service_announcerbut the actual package ispmoves_announcer.✏️ Proposed fix
- from service_announcer import ServiceAnnouncer, announce_service + from pmoves_announcer import ServiceAnnouncer, announce_service
181-182: Don't print raw exception (may leak NATS credentials).Using
print(f"...{e}")can surface credentialized NATS URLs to stdout. Use structured logging without interpolating raw exceptions.🔒 Proposed fix
+import logging + +logger = logging.getLogger(__name__) ... - except Exception as e: - print(f"Failed to announce service: {e}") + except Exception: + logger.exception("Failed to announce service") return False
🧹 Nitpick comments (5)
pmoves_announcer/__init__.py (2)
51-100: Consider using Pydantic for data validation.The
ServiceAnnouncementdataclass accepts untrusted data infrom_json()without validation. Invalid data (wrong types, malformed URLs, negative ports) would be silently accepted. As per coding guidelines, use Pydantic to raise validation errors for data corruption.♻️ Proposed refactor using Pydantic
-from dataclasses import dataclass, field, asdict +from dataclasses import field +from pydantic import BaseModel, Field, field_validator, HttpUrl +from pydantic.dataclasses import dataclass -@dataclass -class ServiceAnnouncement: +class ServiceAnnouncement(BaseModel): """ Service announcement message format for NATS. """ - slug: str name: str - url: str + url: str # or use HttpUrl for strict validation health_check: str tier: ServiceTier - port: int - timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat()) - metadata: Dict[str, Any] = field(default_factory=dict) + port: int = Field(gt=0, le=65535) + timestamp: str = Field(default_factory=lambda: datetime.now(timezone.utc).isoformat()) + metadata: Dict[str, Any] = Field(default_factory=dict) # NATS subject for announcements - SUBJECT: str = "services.announce.v1" + SUBJECT: ClassVar[str] = "services.announce.v1" def to_json(self) -> str: """Convert to JSON for NATS publishing.""" - data = { - "slug": self.slug, - ... - } - return json.dumps(data) + return self.model_dump_json() `@classmethod` def from_json(cls, data: str | dict) -> "ServiceAnnouncement": """Parse from JSON message.""" if isinstance(data, str): data = json.loads(data) - return cls( - slug=data["slug"], - ... - ) + return cls.model_validate(data)
279-283: Background loop silently swallows announce failures.If
announce()returnsFalseor raises an exception, the loop continues without logging. This makes debugging difficult. Consider logging failures or implementing a failure threshold.♻️ Proposed improvement
+import logging + +logger = logging.getLogger(__name__) ... async def _announce_loop(self): """Internal announcement loop.""" while self._running: - await self.announcer.announce() + success = await self.announcer.announce() + if not success: + logger.warning("Background announcement failed, will retry next interval") await asyncio.sleep(self.interval)pmoves_health/__init__.py (3)
30-33:HEALTH_CHECK_TIMEOUTconstant is defined but unused.The timeout constant (5.0s) is defined but individual checks use hardcoded values:
HTTPCheckuses 2.0s (line 83),NATSCheckuses 2s (line 101). Consider using the constant for consistency.♻️ Proposed fix
class HTTPCheck(DependencyCheck): async def check(self) -> bool: try: import httpx - async with httpx.AsyncClient(timeout=2.0) as client: + async with httpx.AsyncClient(timeout=HEALTH_CHECK_TIMEOUT) as client: response = await client.get(self.url) return response.status_code == 200 ... class NATSCheck(DependencyCheck): async def check(self) -> bool: nc = None try: from nats.aio.client import Client as NATS - nc = await NATS.connect(self.nats_url, connect_timeout=2) + nc = await NATS.connect(self.nats_url, connect_timeout=HEALTH_CHECK_TIMEOUT)
121-123: Duplicate checks not prevented.
add_check()appends without checking for duplicates. If the same check is added multiple times (e.g., via multiple decorators or init calls), it will execute repeatedly, slowing health checks.♻️ Proposed fix
def add_check(self, check: DependencyCheck) -> None: """Add a dependency check.""" + # Prevent duplicate checks by name + if any(c.name == check.name for c in self.checks): + return self.checks.append(check)
163-168: Exceptions swallowed without logging.Per retrieved learnings, exceptions should not be silently caught. Consider logging with
logger.exception()for debugging while still returning the failed status.Based on learnings: "Do not silently catch exceptions. Always log with
logger.exception()or re-raise."♻️ Proposed fix
+import logging + +logger = logging.getLogger(__name__) ... except Exception as e: results[check.status_key()] = False + logger.debug("Health check '%s' failed: %s", check.name, type(e).__name__) if check.required: all_healthy = False ... except Exception: results[name] = False + logger.debug("Custom health check '%s' failed", name, exc_info=True) all_healthy = FalseAlso applies to: 177-179
| class ServiceTier(str, Enum): | ||
| """PMOVES service tiers (6-tier architecture).""" | ||
| DATA = "data" | ||
| API = "api" | ||
| LLM = "llm" | ||
| MEDIA = "media" | ||
| AGENT = "agent" | ||
| WORKER = "worker" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find and display ServiceTier definitions in pmoves_announcer
find . -name "*.py" -path "*pmoves_announcer*" | head -20Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 101
🏁 Script executed:
# Search for ServiceTier and registry tier definitions
rg -n "class ServiceTier|ServiceTier\s*=" --type py -A 8 | head -100Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 1027
🏁 Script executed:
# Search for pmoves_registry tier definitions
rg -n "DATA|API|LLM|MEDIA|AGENT|WORKER|APP|UI" --type py -B 2 -A 2 | grep -A 10 "pmoves_registry" | head -50Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 2319
🏁 Script executed:
# Check for Pydantic usage and validation in the codebase
rg -n "pydantic|Pydantic|BaseModel|validator" --type py | head -50Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 4422
🏁 Script executed:
# Look at the actual pmoves_announcer/__init__.py file
cat -n pmoves_announcer/__init__.py | head -60Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 1855
🏁 Script executed:
# Check if ServiceAnnouncement uses Pydantic or just dataclass
cat -n pmoves_announcer/__init__.py | sed -n '51,100p'Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 2047
🏁 Script executed:
# Look for deserialization or announcement parsing logic
rg -n "ServiceAnnouncement|tier|from_dict|parse" pmoves_announcer/__init__.py -A 3 -B 1Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 4007
🏁 Script executed:
# Check if pmoves_registry ever creates announcements
rg -n "ServiceAnnouncer|ServiceAnnouncement" pmoves_registry/__init__.py -A 3 -B 1Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 53
🏁 Script executed:
# Look for any code that might deserialize tier values from strings
rg -n "ServiceTier\(" --type py -B 2 -A 2Repository: POWERFULMOVES/PMOVES-Archon
Length of output: 1247
ServiceTier enum inconsistent with pmoves_registry; add Pydantic validation.
pmoves_registry defines 8 service tiers (lines 28-37), including APP and UI, but pmoves_announcer only defines 6 tiers (lines 41-48). When ServiceAnnouncement.from_json() deserializes a tier value at line 96 (tier=ServiceTier(data["tier"])), it will raise ValueError if the tier is APP or UI. Additionally, per coding guidelines, this file should use Pydantic to raise proper validation errors for data corruption instead of relying on bare Enum() conversion.
Either align the tier definitions or validate tier values with Pydantic before enum instantiation.
🤖 Prompt for AI Agents
In `@pmoves_announcer/__init__.py` around lines 41 - 48, The ServiceTier enum is
missing APP and UI which causes ServiceAnnouncement.from_json
(tier=ServiceTier(data["tier"])) to raise ValueError for valid tiers; update
ServiceTier to include "app" and "ui" entries to match pmoves_registry, and
change ServiceAnnouncement.from_json to rely on Pydantic validation (e.g.,
parse_obj / model instantiation with a Field typed as ServiceTier) instead of
directly calling ServiceTier(...), so invalid values produce Pydantic
ValidationError rather than a bare ValueError.
| try: | ||
| from nats.aio.client import Client as NATS | ||
|
|
||
| announcement = self.create_announcement() | ||
|
|
||
| nc = await NATS.connect(self.nats_url, connect_timeout=5) | ||
| await nc.publish( | ||
| ServiceAnnouncement.SUBJECT, | ||
| announcement.to_json().encode(), | ||
| ) | ||
| await nc.flush() | ||
| await nc.close() | ||
|
|
||
| return True | ||
| except Exception as e: | ||
| print(f"Failed to announce service: {e}") | ||
| return False |
There was a problem hiding this comment.
NATS connection not closed on partial failure.
If nc.publish() or nc.flush() raises an exception after successful connect(), the connection is never closed, causing a resource leak. Use try/finally to ensure cleanup.
🐛 Proposed fix
async def announce(self) -> bool:
"""Publish service announcement to NATS."""
+ nc = None
try:
from nats.aio.client import Client as NATS
announcement = self.create_announcement()
nc = await NATS.connect(self.nats_url, connect_timeout=5)
- await nc.publish(
- ServiceAnnouncement.SUBJECT,
- announcement.to_json().encode(),
- )
- await nc.flush()
- await nc.close()
-
- return True
- except Exception as e:
- print(f"Failed to announce service: {e}")
+ try:
+ await nc.publish(
+ ServiceAnnouncement.SUBJECT,
+ announcement.to_json().encode(),
+ )
+ await nc.flush()
+ return True
+ finally:
+ await nc.close()
+ except Exception:
+ logger.exception("Failed to announce service")
return False🤖 Prompt for AI Agents
In `@pmoves_announcer/__init__.py` around lines 167 - 183, The current announce
flow opens a NATS connection via NATS.connect but if nc.publish() or nc.flush()
raises the connection is never closed; change the logic in the announce routine
to only call NATS.connect first, then wrap the publish/flush sequence in a
try/finally so that await nc.close() always runs when nc was successfully
created; ensure nc is only referenced if connect succeeded (e.g., set nc = None
before connect, assign on success) and guard the await nc.close() in the finally
with a check and swallow/log any errors from close so cleanup never leaks
resources (refer to NATS, connect, nc.publish, nc.flush, nc.close,
create_announcement, ServiceAnnouncement.SUBJECT).
- Neo4j: Remove neo4j:neo4j default credentials - MinIO: Remove minioadmin:minioadmin default credentials - ClickHouse: Remove tensorzero:tensorzero default credentials - Fix typo: export_CACHE_TTL → export CACHE_TTL Empty defaults now require explicit configuration for production use.
Phase 3: Code Quality - Add pmoves_common shared types module (ServiceTier, HealthStatus) - Update ServiceTier imports with fallback to shared module - Remove duplicate ServiceTier enum definitions Phase 4: Documentation - Add comprehensive module docstrings to all integration modules - Create .coderabbit.yaml for automated PR reviews - Enable reviews on feat/* and fix/* branches - Set docstring coverage target to 80% This reduces code duplication and improves type consistency across the PMOVES.AI ecosystem.
…altime feat: LangExtract core + Hi‑RAG v2 hybrid, data IO, Supabase full, realtime UI, avatars
- Add internal: true to pmoves_app network - Add internal: true to pmoves_bus network - Add internal: true to pmoves_monitoring network Security: Isolates internal service communication from external access. Services with published ports can still be accessed via host port mappings. Related: Security review finding #3 - Network Isolation Misconfiguration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created PMOVES-DoX coleam00#96 for PostgreSQL 17 compatibility - Created PMOVES-BoTZ coleam00#51 for TensorZero 2026 migration - Created PMOVES-Agent-Zero #3 for PMOVES.AI integration patterns - Fixed PMOVES-tensorzero to PMOVES.AI-Edition-Hardened branch - Fixed Pmoves-hyperdimensions to PMOVES.AI-Edition-Hardened branch - Verified PMOVES-Wealth on origin/main (fork with upstream) - Cleaned up orphan e2b submodule reference - Created PMOVES.AI-Edition-Hardened-DoX variant branches where needed
- Marked all 3 PRs as merged (DoX coleam00#96, Agent-Zero #3, BoTZ coleam00#51) - Documented feature branch restoration after merge - Added merge conflict resolution details for BoTZ coleam00#51 - Documented keeping hardened MCP server implementation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(pmoves-ai): Add PMOVES.AI integration patterns - Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml) - Add tier-based environment loading (env.shared, env.tier-agent.sh) - Add health check module (pmoves_health/) - Add NATS service announcer (pmoves_announcer/) - Add service registry client (pmoves_registry/) - Add Docker Compose YAML anchors (docker-compose.pmoves.yml) - Add integration documentation (PMOVES.AI_INTEGRATION.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(integration): Apply Phase 1 critical bug fixes - Fix deprecated datetime.utcnow() → datetime.now(timezone.utc) - Fix YAML environment merge (list → map for proper merging) - Fix health check decorator accumulation bug - Fix health endpoint status codes (return 503 when unhealthy) - Remove APP/UI tiers (stick to 6-tier architecture) - Fix resource leaks in NATS connections (try/finally) * fix(security): Remove hardcoded credential defaults - Neo4j: Remove neo4j:neo4j default credentials - MinIO: Remove minioadmin:minioadmin default credentials - ClickHouse: Remove tensorzero:tensorzero default credentials - Fix typo: export_CACHE_TTL → export CACHE_TTL Empty defaults now require explicit configuration for production use. * refactor(code-quality): Phase 3 & 4 improvements Phase 3: Code Quality - Add pmoves_common shared types module (ServiceTier, HealthStatus) - Update ServiceTier imports with fallback to shared module - Remove duplicate ServiceTier enum definitions Phase 4: Documentation - Add comprehensive module docstrings to all integration modules - Create .coderabbit.yaml for automated PR reviews - Enable reviews on feat/* and fix/* branches - Set docstring coverage target to 80% This reduces code duplication and improves type consistency across the PMOVES.AI ecosystem. --------- Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…gration (#12) * Remove Docusaurus documentation system Remove the standalone Docusaurus documentation website to simplify the project structure and reduce maintenance overhead. Changes: - Delete /docs directory (480MB freed) containing all Docusaurus files - Remove docker-compose.docs.yml (optional docs service) - Remove ARCHON_DOCS_PORT from .env.example - Update .github/workflows/release-notes.yml (remove docs section) - Update .github/test-release-notes.sh (remove docs section) Preserved: - Project documents feature (archon-ui-main/src/features/projects/documents/) - Backend document service (python/src/server/services/projects/document_service.py) - Project documents API endpoints (/api/projects/{id}/docs) Benefits: - Eliminates redundancy (content duplicated in /PRPs/ai_docs/) - Reduces complexity (removes 480MB dependencies and configuration) - Simplifies deployment (eliminates optional Docker service on port 3838) - Lowers maintenance burden (single documentation source) All validation tests passed: ✓ File system validation ✓ Backend imports verification ✓ Docker Compose integration testing ✓ CI/CD workflow validation ✓ Project documents API still functional 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add OpenRouter embeddings support Implements OpenRouter as an embedding provider option, enabling access to multiple embedding models (OpenAI, Google Gemini, Qwen3, Mistral) through a single API key. Backend changes: - Add validate_openrouter_api_key() for API key validation (sk-or-v1- format) - Add OpenRouterErrorAdapter for error sanitization - Add openrouter to valid providers in llm_provider_service - Create openrouter_discovery_service with hardcoded model list - Create /api/openrouter/models endpoint for model discovery - Register OpenRouter router in FastAPI main app Frontend changes: - Create openrouterService.ts for model discovery API client - Add OpenRouter to RAGSettings.tsx provider options - Configure default models with provider prefix (openai/text-embedding-3-small) - Add OpenRouter to embedding-capable providers list Documentation: - Update .env.example with OPENROUTER_API_KEY documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add unit tests for OpenRouter model discovery Tests cover: - Model list validation (non-empty, valid types) - Provider prefix validation (all models have provider/) - Data validation (positive dimensions, non-negative pricing) - Provider validation (valid provider names) - Specific provider models (OpenAI, Qwen) - Model ID validation (requires prefix) All 11 tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix embedding provider grid to fit all providers in one line Changed grid-cols-3 to grid-cols-4 for embedding provider selection so all 4 embedding-capable providers (OpenAI, Google, OpenRouter, Ollama) fit on one line, matching the chat provider layout. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix credential_service to recognize OpenRouter as embedding provider Added 'openrouter' to embedding_capable_providers set in credential_service.py to prevent it from being rejected and falling back to OpenAI. Fixes: 'Invalid embedding provider openrouter doesn't support embeddings' error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Address CodeRabbit review: Improve openrouterService robustness 1. Lazy initialization of baseUrl via getBaseUrl() method - Allows API URL to be updated at runtime without stale URL issues 2. Runtime validation of API response structure - Validates embedding_models array exists before caching - Prevents invalid responses from being cached Addresses CodeRabbit nitpick comments on PR coleam00#852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Delete PRPs/openrouter-embeddings-support.md * Add robust cache validation with type guards in openrouterService Implemented comprehensive validation to prevent crashes from corrupted cache: - Created isCacheEntry() type guard to validate cache structure - Parse JSON into unknown type (TypeScript strict mode compliant) - Validate timestamp is number and data has OpenRouterModelListResponse shape - Validate each model has all required fields with correct types - Remove corrupted cache entries to avoid repeated failures - No 'any' types used, full strict mode compliance Prevents crashes from malformed cache data while maintaining type safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add comprehensive API response validation in discoverModels Enhanced validation to catch malformed responses early: - Validate total_count is non-negative number - Verify total_count matches embedding_models.length - Validate first model has required fields (id, provider, dimensions) - Check dimensions are positive numbers - Validate provider names are from expected set - Provide specific error messages for each validation failure Prevents caching invalid data and provides better debugging information. Addresses CodeRabbit nitpick comment on PR coleam00#852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update README for Supabase service role key instructions (coleam00#836) * chore(security): add CODEOWNERS and Dependabot configuration Adds repository security files: - CODEOWNERS for PR review routing - dependabot.yml for automated security updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(hardened): Add nested submodule integrations for standalone operation - Add .gitmodules with 7 nested integrations: - PMOVES-Agent-Zero (agent orchestration) - PMOVES-BoTZ (MCP tools) - PMOVES-HiRAG (knowledge retrieval) - PMOVES-Deep-Serch (deep research) - docling (document processing) - PMOVES-BotZ-gateway (MCP gateway) - PMOVES-tensorzero (TensorZero client) - Fix PydanticAI Agent initialization (remove invalid result_type parameter) Enables Archon to run standalone with PMOVES.AI service connections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(pmoves): add Claude Code MCP adapter for PMOVES.AI integration New module: python/pmoves_mcp/ - claude_code_adapter.py: Async MCP adapter for Claude Code CLI - __init__.py: Module exports Features: - Execute TAC slash commands via Agent Zero's MCP interface - ClaudeCodeMCPAdapter with async httpx client - CommandResult dataclass for structured responses - ARCHON_MCP_TOOLS registration for Archon integration Available commands through adapter: - /search:hirag, /search:supaserch, /search:deepresearch - /health:check-all, /health:metrics - /agents:status, /agents:mcp-query - /deploy:smoke-test, /deploy:services, /deploy:up - /botz:init, /botz:profile, /botz:mcp, /botz:secrets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Restore fail-fast behavior for API key validation in upload - Remove HTTPException catch that was allowing uploads to proceed with invalid credentials - Aligns with beta guidelines: authentication failures should halt execution - Addresses code review feedback from PR #1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(deps): Update uv.lock with dependency revisions - Bump revision from 1 to 3 - Add upload-time fields for PyPI packages - Sync with latest uv dependency resolution 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(observability): add Prometheus metrics endpoint Add /metrics endpoint for Prometheus scraping with: - HTTP request counter (by method, endpoint, status) - HTTP request duration histogram - Knowledge operations counter - MCP commands execution counter 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(search): Add Hi-RAG v2 semantic expansion to keyword extraction - Add optional Hi-RAG v2 integration for knowledge-aware keyword discovery - Enable semantic keyword expansion via PMOVES knowledge graph - Add hirag_url parameter to KeywordExtractor for knowledge graph queries - Improves search relevance with ontology-driven term expansion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(pmoves-ai): Add PMOVES.AI integration patterns (#3) * feat(pmoves-ai): Add PMOVES.AI integration patterns - Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml) - Add tier-based environment loading (env.shared, env.tier-agent.sh) - Add health check module (pmoves_health/) - Add NATS service announcer (pmoves_announcer/) - Add service registry client (pmoves_registry/) - Add Docker Compose YAML anchors (docker-compose.pmoves.yml) - Add integration documentation (PMOVES.AI_INTEGRATION.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(integration): Apply Phase 1 critical bug fixes - Fix deprecated datetime.utcnow() → datetime.now(timezone.utc) - Fix YAML environment merge (list → map for proper merging) - Fix health check decorator accumulation bug - Fix health endpoint status codes (return 503 when unhealthy) - Remove APP/UI tiers (stick to 6-tier architecture) - Fix resource leaks in NATS connections (try/finally) * fix(security): Remove hardcoded credential defaults - Neo4j: Remove neo4j:neo4j default credentials - MinIO: Remove minioadmin:minioadmin default credentials - ClickHouse: Remove tensorzero:tensorzero default credentials - Fix typo: export_CACHE_TTL → export CACHE_TTL Empty defaults now require explicit configuration for production use. * refactor(code-quality): Phase 3 & 4 improvements Phase 3: Code Quality - Add pmoves_common shared types module (ServiceTier, HealthStatus) - Update ServiceTier imports with fallback to shared module - Remove duplicate ServiceTier enum definitions Phase 4: Documentation - Add comprehensive module docstrings to all integration modules - Create .coderabbit.yaml for automated PR reviews - Enable reviews on feat/* and fix/* branches - Set docstring coverage target to 80% This reduces code duplication and improves type consistency across the PMOVES.AI ecosystem. --------- Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * chore: Add GitHub Actions workflows and update submodule SHAs - Add CI/CD workflows: ci.yml, claude-fix.yml, claude-review.yml, release-notes.yml - Update submodule references to latest commits 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(pr): Address CodeRabbit review issues - Fix dependabot.yml: Point pip to /python, npm to /archon-ui-main - Add branch = main to docling submodule in .gitmodules - Add prometheus-client>=0.20.0 to all dependency group 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Sync main to hardened - MCP adapter, CODEOWNERS, nested submodules, persona service Syncs 4 commits from main to PMOVES.AI-Edition-Hardened: - Claude Code MCP adapter for PMOVES.AI integration - CODEOWNERS configuration (security) - Nested submodule integrations for standalone operation - Persona service and API routes for agent creation Includes CodeRabbit review fixes: - Fixed route ordering (/thread-types before /{persona_id}) - Added proper error handling and validation - Removed Git conflict markers - Fixed .coderabbit.yaml configuration 🤖 Generated with Claude Code * docs: add PMOVES.AI skill hints context tags Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore(submodules): update nested PMOVES-HiRAG submodule pointer * security: update PBKDF2 iterations to 600,000 * fix: correct indentation in state_reconciliation.py if-block * fix(env): strip export syntax and add NATS auth to env.shared defaults - Remove `export` prefix from all variables (incompatible with Docker env_file) - Update NATS_URL default to include pmoves credentials - Update usage comment to reflect Docker Compose env_file pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(claude): add CHIT-aware integration context (#9) Co-authored-by: Shaela Bello <slbello@uncg.edu> * fix(auth): align NATS default URLs with credentialed runtime (#10) Co-authored-by: Shaela Bello <slbello@uncg.edu> * chore(submodules): sync HiRAG and BotZ gateway pointers (#11) Co-authored-by: Shaela Bello <slbello@uncg.edu> * fix(security): add USER directive to archon-ui Dockerfile Run as non-root user (uid 65532) to satisfy BuildKit audit and defense-in-depth container hardening requirements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(github): add GitHub App token minting and client Implements GitHub App integration for agent work orders with: - Token minting with JWT RS256 signing (10-min lifetime) - Installation token exchange via GitHub API - Token caching with 50-minute expiry window - GitHubClient with App token + gh CLI fallback - Full test coverage for token minting and PR operations Environment variables required: - GH_APP_ID: GitHub App numeric ID - GH_APP_SEC: PEM private key (handles double-escaped env values) - GH_APP_INSTALLATION_ID: Installation ID for org access Key features: - mint_installation_token(): Creates short-lived JWT + exchanges for token - get_installation_token(): Cached token retrieval with force_refresh option - clear_token_cache(): Manual cache invalidation - GitHubClient.list_pull_requests(): API-first with CLI fallback - Graceful degradation when credentials unavailable Security considerations: - PEM keys stored in env.tier-agent (plaintext - production hardening needed) - No persistent token storage (in-memory cache only) - Short-lived tokens (JWT <10min, installation tokens = 1 hour) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(submodules): promote nested submodule pointers (HiRAG, BotZ-gateway) - external/PMOVES-HiRAG: 89d4abf→e904b12 (CHIT + geometry bus context, PR #4) - pmoves_multi_agent_pro_pack/PMOVES-BotZ-gateway: 40e1e33→2565022 (log sanitizer, PR #4) Both commits are merged on their respective origin/main branches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(submodules): recover nested wipes + promote BoTZ skill pointers - Recovered 3 wiped nested subs: Deep-Serch (88 files), tensorzero (2906 files), docling (839 files) — same wipe pattern as Phase 5 - Recovered 6 wiped sub-sub-subs inside nested BoTZ copy - Promoted 7 skill repo pointer advances in nested BoTZ copy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: leex279 <thomas@thirty3.de> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: sean-eskerium <sean@eskerium.com> Co-authored-by: Jason Pickens <jasonpickensnz@gmail.com> Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com> Co-authored-by: PMOVES.AI <claude@pmoves.ai> Co-authored-by: Shaela Bello <slbello@uncg.edu>
Summary
This PR adds PMOVES.AI integration patterns to PMOVES-Archon, enabling seamless integration with the parent PMOVES.AI platform.
Integration Components
CHIT Secrets Management
chit/secrets_manifest_v2.yamlfor compressed secrets handlingTier-Based Environment Loading
env.shared- Base PMOVES.AI service configuration (~6000 lines)env.tier-agent.sh- Agent tier specific environment variablesService Discovery
pmoves_announcer/- NATS service announcement modulepmoves_registry/- Service registry client with fallback chainHealth Endpoints
pmoves_health/- Comprehensive health check moduleDocumentation
PMOVES.AI_INTEGRATION.md- Integration guide and checklistdocker-compose.pmoves.yml- PMOVES.AI YAML anchorsTesting
Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.